namespace js_base_day3 {



    // for语句的基本使用, 3 要素
    for (let i: number = 0; i <= 6; i++) {
        document.write(`<h${i}>循环控制，即重复执行<h${i}>`)
    }

    // 1. continue 跳出循环
    for (let i: number = 0; i <= 5; i++) {
        if (i === 3) {
            continue // 结束本次循环，继续下一次循环
        }
        console.log('continue-i', i); // 0 1 2 4 5
    }
    // 2. break 终止循环
    for (let i: number = 0; i <= 5; i++) {
        if (i === 3) {
            break // 退出结束整个循环
        }
        console.log('break-i', i); // 0 1 2

    }


    // 循环嵌套

    // 1. 外面的循环 记录第n天 
    for (let i: number = 1; i < 4; i++) {
        document.write(`第${i}天 <br>`)
        // 2. 里层的循环记录 几个单词
        for (let j: number = 1; j < 6; j++) {
            document.write(`记住第${j}个单词<br>`)
        }
    }
    // 记住，外层循环循环一次，里层循环循环全部

    // 倒三角
    // 外层打印几行
    for (let i: number = 1; i <= 5; i++) {
        // 内层打印几个星星
        for (let j: number = 1; j <= i; j++) {
            document.write('★')
        }
        document.write('<br>')
    }

    // 九九乘法表
    for (let i: number = 1; i <= 9; i++) {
        for (let j: number = 1; j <= i; j++) {
            document.write(`<span style="padding: 5px;"> ${j} * ${i} = ${j * i}</span>`)
        }
        document.write(`<br>`)
    }

    // 数组

    // 定义数组和数组单元

    // 1. 语法，使用[] 来定义一个空数组
    // 定义一个空数组，然后赋值给变量 classes
    let classes1: any[] = []

    // 2、定义非空数组
    let classes2: string[] = ['小明', '小刚', '小红', '小丽', '小米']

    document.write(classes2[0]) // 小明
    document.write(classes2[1]) // 小刚
    document.write(classes2[3]) // 小丽
    document.write(classes2[4]) // 小米
    classes2[4] = '大米'
    document.write(classes2[4]) // 大米


    // 数据单元值类型
    // 数组做为数据的集合，它的单元值可以是任意数据类型

    let list: string[] = ['HTML', 'CSS', 'JavaScript']
    let scores: number[] = [78, 84, 70, 62, 75]
    let mixin: (string | number | boolean)[] = [true, 1, false, 'hello']

    let arr: string[] = ['html', 'css', 'javascript']
    console.log(arr.length) // 3
    // 1. push 动态向数组的尾部添加一个单元
    arr.push('Nodejs')
    arr.push('Vue')
    console.log(arr) // ['html', 'css', 'javascript', 'Nodejs', 'Vue']
    // 2. unshit 动态向数组头部添加一个单元
    arr.unshift('VS Code')
    console.log(arr) // ['VS Code', 'html', 'css', 'javascript', 'Nodejs', 'Vue']
    // 3. splice 动态删除任意单元
    arr.splice(2, 1) // 从索引值为 2的位置开始删除1个单元
    console.log(arr) // ['VS Code', 'html', 'javascript', 'Nodejs', 'Vue']
    // 4. pop 删除最后一个单元
    arr.pop()
    console.log(arr) // ['VS Code', 'html', 'javascript', 'Nodejs']
    // 5. shift 删除第一个单元
    arr.shift()
    console.log(arr) // ['html', 'javascript', 'Nodejs']


    // 一、for 循环遍历
    for (let i: number = 0; i < 5; i++) {
        console.log(i); // 0 1 2 3 4
    }

    const array1: string[] = ['a', 'b', 'c', 'd']
    for (let i: number = 0; i <= arr.length; i++) {
        console.log(array1[i]); // a b c d 
    }

    // 二、for ... of 方法
    let array2: number[] = [1, 2, 3, 4, 5]
    for (let item of array2) {
        console.log(item); // 1 2 3 4 5
    }

    // 三、for...in循环
    interface Person {
        name: string,
        age: number,
        gender: string
    }

    let p1: Person = {
        name: 'Tom',
        age: 18,
        gender: 'male'
    }

    for (let item in p1) {
        if (p1.hasOwnProperty(item)) {
            console.log(`${item}: ${p1[item as keyof Person]}`);
            // console.log(`${item}: ${Object.values(p1)}`);
            //作为一种显式的类型注解，它向读者表明了:item应该是Person接口的一个键。
        }
    }



    // 四、forEach 遍历
    let arr2: number[] = [1, 2, 3, 4]
    arr2.forEach((item: number) => {
        item = item * 2;
    });
    console.log(arr2); // [1, 2, 3, 4]


    // 五、map 映射
    let number: number[] = [1, 2, 3, 4, 5];
    let doubleNumbers = number.map(function (num: number) {
        return num * 2
    })
    console.log(doubleNumbers); // [2, 4, 6, 8, 10]

    // 六、filter方法
    let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    let filterNumbers = numbers.filter((num: number) => {
        return num >= 5
    })
    console.log(filterNumbers); // [5, 6, 7, 8, 9, 10]

    // 七、reduce高阶函数（迭代（累加器））
    let numbers2 = [1, 2, 3, 4, 5];
    let sum = numbers2.reduce((total: number, num: number) => {
        return total + num
    }, 0)
    console.log(sum); // 15

    // 八、every
    // 遍历数组，每一个元素都满足条件 则返回 true，否则返回 false

    // 九、some
    // 对数组中每个元素执行一次function 函数，直到某个元素返回true，则直接返回true。如果都返回false, 则返回false
    function some(id: number) {
        const arr3: { cityId: number, cityName: string }[] = [
            { cityId: 195, cityName: '深圳' },
            { cityId: 196, cityName: '北京' },
            { cityId: 198, cityName: '上海' }
        ]
        let result = arr3.some((item) => {
            return item.cityId === id
        })
        console.log(`传入：${id},结果：${result}`);

    }
    some(2) // 传入：2,结果：false
    some(196) // 传入：196,结果：true

    // 十、find
    // 遍历数组，返回符合条件的第一个元素，如果没有符合条件的元素则返回 undefined
    let arr4 = [1, 2, 2, 3, 3, 3, 3, 4, 4, 5, 6]
    let num = arr4.find((item: number) => {
        return item === 3
    })
    console.log(num); // 3


    // 十一、findIndex
    // findIndex() 方法返回数组中满足提供的测试函数的第一个元素的索引。 
    // 如果没有找到符合条件的元素，则返回 - 1
    const arr5 = [5, 12, 8, 130, 44];
    let index = arr5.findIndex((item: number) => item > 13)
    console.log(index); // 3

    // 对象遍历 entries(), keys(), values()

    // entries()
    // entries() 方法返回一个迭代器，它包含对象自身的（不含继承的）所有可枚举属性的键值对数组。对于 Map 对象，它返回键值对的迭代器。

    let obj: { a: number, b: number } = { a: 1, b: 2 };
    let map: Map<string, string> = new Map([
        ['key1', 'value1'],
        ['key2', 'value2']
    ]);

    // 对象的 entries()
    for (let [key, value] of Object.entries(obj)) {
        console.log(`${key}: ${value}`); // 输出 "a: 1" 和 "b: 2"
    }

    // Map 的 entries()
    for (let [key, value] of map.entries()) {
        console.log(`${key}: ${value}`); // 输出 "key1: value1" 和 "key2: value2"
    }


    // keys()
    // keys() 方法返回一个迭代器，它包含对象自身的（不含继承的）所有可枚举属性的键。

    let obj2: { a: number, b: number } = { a: 1, b: 2 };
    for (let key of Object.keys(obj2)) {
        console.log(key); // a b

    }
    // 注意：Map 对象没有 keys() 方法，因为它的迭代器默认就是返回键。


    // values()
    // values() 方法返回一个迭代器，它包含对象自身的（不含继承的）所有可枚举属性的值。
    let obj3: { a: number, b: number } = { a: 1, b: 2 }

    for (let value of Object.values(obj3)) {
        console.log(value); // 1 2

    }

    // 链式调用
    const arr6: { name: string, byuse: string, gongji: number }[] = [
        {
            name: '青龙偃月刀',
            byuse: '关羽',
            gongji: 1000
        },
        {
            name: '龙胆亮银枪',
            byuse: '赵子龙',
            gongji: 2000
        },
        {
            name: '丈八蛇矛',
            byuse: '张飞',
            gongji: 999
        },
        {
            name: '雌雄对剑',
            byuse: '刘备',
            gongji: 60
        },
        {
            name: '方天画戟',
            byuse: '吕布',
            gongji: 99999
        },
    ]
    // 给所有的武器攻击 * 2  ，还低于1000 淘汰， 把2倍后超过1000武力值加载一起

    let arrMap = arr6.map((item: { name: string, byuse: string, gongji: number }) => {
        return { name: item.name, byuse: item.byuse, gongji: item.gongji * 2 }
    })
    console.log(arrMap);

    let arrfilter = arrMap.filter((item: { name: string, byuse: string, gongji: number }) => item.gongji >= 1000)
    console.log(arrfilter);


    let arrReduce = arrfilter.reduce((total, item) => total + item.gongji, 0)
    console.log(arrReduce); // 207996

    // 链式调用: 返回值是 最后链式调用的函数返回的值
    let reduceNum = arr6.map((item) => {
        return { name: item.name, byuse: item.byuse, gongji: item.gongji * 2 }
    }).filter((item) => {
        return item.gongji >= 1000
    }).reduce((total, item) => { return total + item.gongji }, 0)
    console.log(reduceNum); // 207996

    // 对整个数组循环，判断每一项是否符合条件，以一个不符合 就返回false
    let b1 = arr6.every(function (item, index, self) {
        return item.gongji > 1000
    });
    console.log(b1); // false

    const b2 = arr6.some((item) => {
        return item.name === '青釭剑'
    })
    console.log(b2); // false

    let item1 = arr6.find((item) => {
        return item.gongji >= 2000
    })
    console.log(item1); // {name: '龙胆亮银枪', byuse: '赵子龙', gongji: 2000}

    let itemIndex = arr6.findIndex((item) => {
        return item.gongji >= 2000
    })
    console.log(itemIndex); // 1
    arr.splice(itemIndex, 1)
    console.log(arr); // ['html', 'Nodejs']











    // 案例
    // for...of 案例

    // 案例 1：过滤数组中的奇数并输出 （封装）
    function filterOdd(arr: number[]): void {
        for (let num of arr) {
            if (num % 2 !== 0) {
                console.log(num); // 1 3 5 7 9
            }
        }
    }
    const numbers3: number[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    filterOdd(numbers3)

    // 案例 2：查找并输出字符串数组中包含特定子字符串的元素 （封装）
    function findString(arr: string[]) {
        for (let str of arr) {
            if (str.includes('is')) {
                console.log(str); // javascript is fun , coding is great
            }
        }
    }

    const phrases: string[] = ['hello world', 'javascript is fun', 'openai gpt', 'coding is great'];
    findString(phrases)

    // 案例 3：计算并输出包含负数的数组的正数总和 （封装）
    function total(arr: number[]) {
        let sum = 0
        for (const num of arr) {
            if (num > 0) {
                sum += num
            }
        }
        console.log(sum); // 20

    }
    const mixedNumbers: number[] = [-3, 5, -1, 8, -2, 7];
    total(mixedNumbers)



    // for...in 案例

    // 案例 1：遍历对象属性并输出符合条件的属性值
    interface Person1 {
        name: string,
        age: number,
        city: string,
        occupation: string
    }
    const person: Person1 = {
        name: 'Alice',
        age: 25,
        city: 'Wonderland',
        occupation: 'Engineer'
    };
    function findString2(obj: Person1) {
        for (const key in obj) {
            if (typeof obj[key as keyof Person1] === 'string') {
                console.log(obj[key as keyof Person1]);
            }
        }
    }
    findString2(person)

    // 案例 2：计算对象中数值属性的总和
    interface Da {
        a: number,
        b: number,
        c: string,
        d: number,
        e: string
    }
    const data: Da = {
        a: 10,
        b: 20,
        c: 'thirty',
        d: 40,
        e: 'fifty'
    };
    function objNum(obj: Da) {
        let sum: number = 0
        for (const key in obj) {
            if (typeof obj[key as keyof Da] === 'number') {
                console.log(obj[key as keyof Da]); // 10 20 40
                // sum += obj[key as keyof Da]
                sum += Number(obj[key as keyof Da]) // 70
            }
        }
        console.log(`Total sum of numeric values: ${sum}`);
    }
    objNum(data)


    // 案例 3：查找对象中符合条件的属性并输出键和值
    interface Invent {
        apples: number,
        oranges: number,
        bananas: number,
        grapes: number,
        cherries: number
    }
    const inventory: Invent = {
        apples: 5,
        oranges: 0,
        bananas: 8,
        grapes: 2,
        cherries: 0
    };
    function findkey(obj: Invent) {
        for (const key in obj) {
            if (obj[key as keyof Invent] === 0) {
                console.log(`${key}: ${obj[key as keyof Invent]}`); // oranges: 0 , cherries: 0
            }
        }
    }
    findkey(inventory)


    // forEach 案例
    // 案例 1：查找并输出数组中的正数并计算它们的平均值


    function findnum(arr: number[]) {
        let sum = 0
        let count = 0
        arr.forEach(item => {
            if (item > 0) {
                sum += item
                count++
            }
        })
        const average: number = sum / count
        console.log(`Average of positive numbers: ${average}`); // Average of positive numbers: 7

    }
    const numbers4: number[] = [-3, 5, -1, 8, -2, 8];
    findnum(numbers4)

    // 案例 2：查找数组中的字符串长度并输出超过特定长度的字符串
    function findLength(arr: string[]): void {
        const minLength = 5;
        words.forEach(item => {
            if (item.length > minLength) {
                console.log(item); // banana cherry
            }
        });
    }
    const words: string[] = ['apple', 'banana', 'cherry', 'date', 'fig', 'grape'];
    findLength(words)

    // map 案例
    // - 案例 1：将数组中的负数转换为正数
    function getnums(arr: number[]): void {
        let newArr: number[] = arr.map(item => {
            return item < 0 ? -item : item
        })
        console.log(newArr); // [3, 5, 1, 8, 2, 7]

    }
    const numbers5: number[] = [-3, 5, -1, 8, -2, 7];
    getnums(numbers5)


    // 案例 2：将对象数组中的特定属性值大写化 
    interface Person2 {
        name: string
        age: number
    }
    const people: Person2[] = [
        { name: 'Alice', age: 25 },
        { name: 'Bob', age: 30 },
        { name: 'Charlie', age: 35 }
    ];
    function getToUpWords(obj: Person2[]) {
        const upWords = obj.map(item => {
            return item.name.length > 3 ? { ...item, name: item.name.toUpperCase() } : item;
        })
        console.log(upWords);

    }
    getToUpWords(people)

    // 案例 3：将字符串数组中的特定子字符串替换为另一字符串
    function updateString(arr: string[]) {
        const updateStr = arr.map(item => {
            return item.includes('hello') ? item.replace('hello', 'hi') : item
        })
        console.log(updateStr); // ['hi world', 'javascript is fun', 'hi openai', 'coding is great']

    }
    const phrases2: string[] = ['hello world', 'javascript is fun', 'hello openai', 'coding is great'];
    updateString(phrases2)


    // 使用 map、filter 和 reduce 方法结合的案例
    // 案例 1：计算并输出长度大于 5 的字符串的总长度 
    function getLength(arr: string[]) {
        const lengthTotal =
            arr.filter(item => item.length > 5)  // 过滤长度大于5的字符串
                .map(item => item.length)  // 将度大于5的字符串转换为其长度
                .reduce((sum, length) => sum + length, 0)  // 计算总长度
        console.log(lengthTotal); // 40


    }
    const phrases3 = ['hello world', 'javascript', 'openai', 'coding is fun'];
    getLength(phrases3)


    // 案例 2：计算正数数组的平方和，并排除负数 
    function getSquares(arr: number[]) {
        const Squares = arr.filter(item => item > 0).map(item => item * item).reduce((sum, square) => sum + square, 0)
        console.log(Squares); // 61

    }
    const numbers6: number[] = [-5, 3, -2, 4, 6, -1];
    getSquares(numbers6)


    // 案例 3：处理用户数据，提取年龄大于 18 的用户，并计算他们的平均年龄
    interface User {
        name: string
        age: number
    }
    const users: User[] = [
        { name: 'Alice', age: 22 },
        { name: 'Bob', age: 17 },
        { name: 'Charlie', age: 30 },
        { name: 'David', age: 15 }
    ];
    function getUsers(arr: User[]) {
        const average = arr.filter(item => item.age > 18).map(item => item.age).reduce((sum, age, index, array) => sum + age / array.length, 0)
        console.log(average); // 26

    }
    getUsers(users)


    // 使用 findIndex、splice 方法结合案例

    // - 案例 1：在购物车中移除指定商品   
    interface Cart {
        id: number
        name: string
        quantity: 1 | 2
    }
    const cart: Cart[] = [
        { id: 1, name: 'Laptop', quantity: 1 },
        { id: 2, name: 'Mouse', quantity: 2 },
        { id: 3, name: 'Keyboard', quantity: 1 }
    ];
    function removeCart(arr: Cart[]) {
        const itemIdToRemove = 2; // 指定要移除的商品id
        const indexToRemove = arr.findIndex(item => item.id === itemIdToRemove)
        console.log(indexToRemove); // 1

        if (indexToRemove !== -1) {
            arr.splice(indexToRemove, 1)
        }
        console.log(arr);// [{id: 1, name: 'Laptop', quantity: 1},{id: 3, name: 'Keyboard', quantity: 1}]

    }
    removeCart(cart)


    // 案例 2：更新数组中的指定对象属性
    interface Person3 {
        id: number
        name: string
        role: string
    }
    const employees: Person3[] = [
        { id: 1, name: 'John', role: 'Developer' },
        { id: 2, name: 'Jane', role: 'Designer' },
        { id: 3, name: 'Tom', role: 'Manager' }
    ];
    function updateKey(arr: Person3[]) {
        const employeeIdToUpdate = 3;
        const newRole = 'Senior Manager';
        const indexToUpdate = arr.findIndex(item => item.id === employeeIdToUpdate)
        console.log(indexToUpdate); // 2
        if (indexToUpdate !== -1) {
            arr[indexToUpdate].role = newRole
        }
        console.log(arr);

    }
    updateKey(employees)

    // 案例 3：将数组中的第一个负数替换为零
    function getReplace(arr: number[]) {
        const indexToReplace = arr.findIndex(item => item < 0)
        console.log(indexToReplace); // 1
        if (indexToReplace !== -1) {
            arr.splice(indexToReplace, 1, 0)
        }
        console.log(arr); // [4, 0, 6, -2, 7]


    }
    const numbers7: number[] = [4, -1, 6, -2, 7];
    getReplace(numbers7)

}


